import pyautogui
import cv2
import numpy as np
import time
import pytesseract
import win32gui
import win32con
import dxcam
import os
import json
import re
from PIL import Image
from difflib import SequenceMatcher
from collections import deque

# ===== 配置区域 =====
PLAYER_WINDOW_TITLE = "EVPlayer2"  # 修改为实际播放器窗口标题
END_PAGE_IMAGE = './logo.png'
CONFIDENCE_THRESHOLD = 0.8
CHECK_INTERVAL = 5
TEXT_TRIGGERS = ["播放结束", "THE END", "播放完毕", "重播", "视频播放结束", "END"]
TESSERACT_PATH = r'D:\Program Files\Tesseract-OCR\tesseract.exe'  # Windows路径

# 目录区域配置 (相对于播放器窗口)
DIRECTORY_REGION = (800, 100, 400, 600)  # (x, y, width, height)

# 目录项特征
ITEM_HEIGHT = 30         # 每个目录项的大致高度
FOLDER_ICON = 'icons/folder.png'  # 文件夹图标特征图
VIDEO_ICON = 'icons/video.png'    # 视频图标特征图
EXPANDED_ICON = 'icons/expanded.png'  # 展开状态的图标
COLLAPSED_ICON = 'icons/collapsed.png' # 折叠状态的图标
# ===== 配置结束 =====

# 状态存储
camera = None
current_video = ""    # 当前播放的视频名称
video_history = []    # 播放历史
completed_videos = set()  # 已播放完成的视频集合

def init_dxcam():
    global camera
    try:
        camera = dxcam.create()
        return camera is not None
    except Exception as e:
        print(f"初始化dxcam失败: {e}")
        return False

def get_player_window_rect():
    """获取播放器窗口位置和大小"""
    def callback(hwnd, extra):
        if win32gui.IsWindowVisible(hwnd):
            window_title = win32gui.GetWindowText(hwnd)
            if PLAYER_WINDOW_TITLE in window_title:
                rect = win32gui.GetWindowRect(hwnd)
                extra['rect'] = rect
                extra['hwnd'] = hwnd
    extra_info = {'rect': None, 'hwnd': None}
    win32gui.EnumWindows(callback, extra_info)
    
    if not extra_info['rect']:
        return None, None
    
    left, top, right, bottom = extra_info['rect']
    width = right - left
    height = bottom - top
    return extra_info['hwnd'], (left, top, width, height)

def capture_window_region(region):
    """捕获指定区域"""
    if not camera:
        return None
    left, top, width, height = region
    capture_region = (left, top, left + width, top + height)
    try:
        img = camera.grab(region=capture_region)
        if img is None:
            return None
        return cv2.cvtColor(img, cv2.COLOR_BGRA2RGB)
    except:
        return None

def image_detected(screen_np, template_path, threshold=CONFIDENCE_THRESHOLD):
    """图像模板匹配检测"""
    try:
        template = cv2.imread(template_path, cv2.IMREAD_GRAYSCALE)
        if template is None:
            return False
        gray_screen = cv2.cvtColor(screen_np, cv2.COLOR_RGB2GRAY)
        result = cv2.matchTemplate(gray_screen, template, cv2.TM_CCOEFF_NORMED)
        _, max_val, _, _ = cv2.minMaxLoc(result)
        return max_val >= threshold
    except:
        return False

def image_to_text(image_np):
    """从图像中提取文本"""
    try:
        gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
        _, threshold = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
        text = pytesseract.image_to_string(threshold, lang='chi_sim+eng')
        
        # 清理OCR结果
        text = re.sub(r'[^\w\s\-()\[\]{}]', '', text).strip()
        return text
    except:
        return ""

def text_similarity(a, b):
    """计算文本相似度"""
    a = re.sub(r'\W+', '', a).lower()
    b = re.sub(r'\W+', '', b).lower()
    if not a or not b:
        return 0.0
    return SequenceMatcher(None, a, b).ratio()

def activate_window(hwnd):
    """激活播放器窗口"""
    if hwnd:
        if win32gui.IsIconic(hwnd):
            win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
        win32gui.SetForegroundWindow(hwnd)
        time.sleep(0.5)

def get_directory_structure(window_rect):
    """分析右侧目录结构"""
    # 计算目录区域绝对坐标
    dir_left = window_rect[0] + DIRECTORY_REGION[0]
    dir_top = window_rect[1] + DIRECTORY_REGION[1]
    dir_width = DIRECTORY_REGION[2]
    dir_height = DIRECTORY_REGION[3]
    dir_region = (dir_left, dir_top, dir_width, dir_height)
    
    # 截取目录区域
    dir_img = capture_window_region(dir_region)
    if dir_img is None:
        return []
    
    # 保存目录截图用于调试
    os.makedirs("debug", exist_ok=True)
    Image.fromarray(dir_img).save("debug/directory_snapshot.png")
    
    # 识别目录项
    gray_dir = cv2.cvtColor(dir_img, cv2.COLOR_RGB2GRAY)
    _, binary_dir = cv2.threshold(gray_dir, 150, 255, cv2.THRESH_BINARY)
    
    # 查找轮廓 (目录项)
    contours, _ = cv2.findContours(binary_dir, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    items = []
    for contour in contours:
        x, y, w, h = cv2.boundingRect(contour)
        
        # 过滤太小的元素
        if w < 50 or h < 10 or w > dir_width * 0.9:
            continue
        
        # 提取整个目录项图像
        item_img = dir_img[y:y+h, x:x+w]
        
        # 识别图标类型
        item_type = "unknown"
        if image_detected(item_img, FOLDER_ICON, 0.7):
            item_type = "folder"
        elif image_detected(item_img, VIDEO_ICON, 0.7):
            item_type = "video"
        
        # 识别展开状态
        expanded = None
        if item_type == "folder":
            # 检查左侧小图标区域 (假设图标在左侧20像素内)
            icon_region = item_img[:, :20]
            if image_detected(icon_region, EXPANDED_ICON, 0.7):
                expanded = True
            elif image_detected(icon_region, COLLAPSED_ICON, 0.7):
                expanded = False
        
        # 识别文本区域（假设文本在右侧）
        text_region = item_img[:, 30:]  # 跳过左侧30像素（图标区域）
        
        # 识别文本
        text = image_to_text(text_region).strip()
        
        # 检查是否已完成播放
        is_completed = text in completed_videos
        
        items.append({
            "x": x + dir_left,
            "y": y + dir_top,
            "width": w,
            "height": h,
            "text": text,
            "type": item_type,
            "expanded": expanded,
            "completed": is_completed
        })
    
    # 按Y坐标排序
    items.sort(key=lambda item: item["y"])
    
    # 保存调试信息
    debug_img = dir_img.copy()
    for item in items:
        if item["type"] == "video":
            color = (100, 100, 255) if item["completed"] else (0, 255, 0)
        else:  # folder
            if item["expanded"] is True:
                color = (255, 165, 0)  # 橙色 - 展开
            elif item["expanded"] is False:
                color = (255, 0, 0)    # 红色 - 折叠
            else:
                color = (128, 128, 128) # 灰色 - 未知
        
        cv2.rectangle(debug_img, (item["x"]-dir_left, item["y"]-dir_top), 
                     (item["x"]-dir_left+item["width"], item["y"]-dir_top+item["height"]), 
                     color, 2)
        label = f"{item['text']} {'(完成)' if item.get('completed') else ''}"
        cv2.putText(debug_img, label, 
                   (item["x"]-dir_left, item["y"]-dir_top-10), 
                   cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)
    
    Image.fromarray(debug_img).save("debug/directory_debug.png")
    
    return items

def find_next_video(directory_items, current_video_title):
    """在目录中查找下一个视频"""
    # 查找当前播放完成的视频
    current_index = -1
    for i, item in enumerate(directory_items):
        if item["type"] == "video" and text_similarity(item["text"], current_video_title) > 0.7:
            current_index = i
            break
    
    if current_index == -1:
        print(f"未找到当前视频: {current_video_title}")
        return None
    
    # 从当前视频之后开始查找
    for i in range(current_index + 1, len(directory_items)):
        item = directory_items[i]
        
        # 如果是视频且未播放过
        if item["type"] == "video" and not item["completed"]:
            return item
        
        # 如果是折叠的文件夹
        if item["type"] == "folder" and item["expanded"] is False:
            return item
    
    # 如果后面没有找到，尝试从列表开头查找
    for i in range(0, current_index):
        item = directory_items[i]
        if item["type"] == "video" and not item["completed"]:
            return item
        if item["type"] == "folder" and item["expanded"] is False:
            return item
    
    return None

def expand_folder_and_find_video(folder_item, window_rect):
    """展开文件夹并查找其中的视频"""
    print(f"展开文件夹: {folder_item['text']}")
    
    # 点击展开文件夹
    click_directory_item(folder_item)
    time.sleep(1.5)  # 等待展开动画
    
    # 重新获取目录结构
    new_directory_items = get_directory_structure(window_rect)
    
    # 查找当前文件夹项
    folder_index = -1
    for i, item in enumerate(new_directory_items):
        if (item["type"] == "folder" and 
            text_similarity(item["text"], folder_item["text"]) > 0.9 and
            item["expanded"] is True):
            folder_index = i
            break
    
    if folder_index == -1:
        print("无法找到展开的文件夹")
        return None
    
    # 查找文件夹下的第一个未播放视频
    for i in range(folder_index + 1, len(new_directory_items)):
        item = new_directory_items[i]
        
        # 如果层级已经回到文件夹同级或更高，说明已离开文件夹
        if item["y"] - folder_item["y"] > ITEM_HEIGHT * 5:  # 简单层级判断
            break
        
        if item["type"] == "video" and not item["completed"]:
            return item
    
    print("文件夹内未找到未播放的视频")
    return None

def click_directory_item(item):
    """点击目录项"""
    # 计算点击位置（中心偏左，避免点到图标）
    click_x = item["x"] + 20
    click_y = item["y"] + item["height"] // 2
    
    # 激活窗口
    hwnd, _ = get_player_window_rect()
    activate_window(hwnd)
    
    # 点击
    pyautogui.moveTo(click_x, click_y, duration=0.3)
    pyautogui.click()
    print(f"已点击: {item['text']}")

def handle_video_end(window_rect):
    """视频结束处理"""
    global current_video
    
    if not current_video:
        print("当前视频未设置，无法处理结束")
        return
    
    print(f"✅ 检测到视频结束: {current_video}")
    
    # 标记当前视频为已完成
    completed_videos.add(current_video)
    
    # 保存状态
    save_state()
    
    # 获取目录结构
    directory_items = get_directory_structure(window_rect)
    if not directory_items:
        print("⚠️ 无法获取目录结构")
        return
    
    # 查找下一个播放目标
    next_target = find_next_video(directory_items, current_video)
    
    if not next_target:
        print("⚠️ 未找到下一个播放目标")
        return
    
    # 处理不同类型的目标
    if next_target["type"] == "video":
        print(f"找到下一个视频: {next_target['text']}")
        click_directory_item(next_target)
        current_video = next_target["text"]
        print(f"⏭ 已跳转到下一个视频: {current_video}")
    
    elif next_target["type"] == "folder" and next_target["expanded"] is False:
        # 展开文件夹并查找其中的视频
        video_item = expand_folder_and_find_video(next_target, window_rect)
        if video_item:
            click_directory_item(video_item)
            current_video = video_item["text"]
            print(f"⏭ 已跳转到文件夹内的视频: {current_video}")
        else:
            print("无法在文件夹内找到可播放的视频")
    
    # 等待新视频开始
    time.sleep(10)

def capture_end_page_image():
    """截取结束页面作为模板"""
    print("请确保视频处于结束页面状态...")
    time.sleep(5)
    
    hwnd, window_rect = get_player_window_rect()
    if not hwnd:
        return
    
    screenshot = capture_window_region(window_rect)
    if screenshot is None:
        return
    
    Image.fromarray(screenshot).save(END_PAGE_IMAGE)
    print(f"已保存结束页面截图: {END_PAGE_IMAGE}")

def get_current_video_title():
    """尝试从播放器窗口标题获取当前视频"""
    hwnd, _ = get_player_window_rect()
    if hwnd:
        title = win32gui.GetWindowText(hwnd)
        # 尝试从标题中提取视频名称
        patterns = [
            r'(.+?)\s*[-|—]\s*' + re.escape(PLAYER_WINDOW_TITLE),
            r'(.+?)\s*[-|—]\s*播放',
            r'正在播放:\s*(.+)'
        ]
        
        for pattern in patterns:
            match = re.search(pattern, title)
            if match:
                return match.group(1).strip()
        
        # 如果无法提取，返回完整标题
        return title
    return ""

def save_state():
    """保存当前状态"""
    with open("video_state.json", "w") as f:
        json.dump({
            "current_video": current_video,
            "completed_videos": list(completed_videos),
            "history": video_history
        }, f)

def load_state():
    """加载保存的状态"""
    global current_video, completed_videos, video_history
    if os.path.exists("video_state.json"):
        with open("video_state.json", "r") as f:
            data = json.load(f)
            current_video = data.get("current_video", "")
            completed_videos = set(data.get("completed_videos", []))
            video_history = data.get("history", [])
            print(f"已加载状态: {len(completed_videos)}个已完成视频")

def setup_icons():
    """设置图标路径"""
    global FOLDER_ICON, VIDEO_ICON, EXPANDED_ICON, COLLAPSED_ICON
    icon_dir = "icons"
    os.makedirs(icon_dir, exist_ok=True)
    
    # 如果图标不存在，使用默认值
    FOLDER_ICON = os.path.join(icon_dir, "folder.png")
    VIDEO_ICON = os.path.join(icon_dir, "video.png")
    EXPANDED_ICON = os.path.join(icon_dir, "expanded.png")
    COLLAPSED_ICON = os.path.join(icon_dir, "collapsed.png")
    
    # 创建默认图标文件（如果不存在）
    default_icons = {
        "folder.png": [
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 1, 1, 0, 0, 0, 0, 1, 1, 0],
            [0, 1, 1, 0, 0, 0, 0, 1, 1, 0],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ],
        "video.png": [
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
            [0, 1, 0, 0, 1, 1, 0, 0, 1, 0],
            [0, 1, 0, 0, 1, 1, 0, 0, 1, 0],
            [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
            [0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
        ],
        "expanded.png": [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 1, 1, 1, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0]
        ],
        "collapsed.png": [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 1, 1, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ]
    }
    
    for icon_name, icon_data in default_icons.items():
        icon_path = os.path.join(icon_dir, icon_name)
        if not os.path.exists(icon_path):
            # 创建简单的图标
            img_data = np.array(icon_data, dtype=np.uint8) * 255
            img = Image.fromarray(img_data)
            img.save(icon_path)
            print(f"已创建默认图标: {icon_path}")

def main():
    global current_video
    
    # 创建必要的目录
    os.makedirs("debug", exist_ok=True)
    
    # 设置图标路径
    setup_icons()
    
    # 设置Tesseract
    pytesseract.pytesseract.tesseract_cmd = TESSERACT_PATH
    
    # 加载状态
    load_state()
    
    # 初始化截图库
    if not init_dxcam():
        print("初始化失败，退出程序。")
        return
    
    # 首次运行帮助
    if not os.path.exists(END_PAGE_IMAGE):
        if input("是否需要截取结束页面图像? (y/n): ").lower() == 'y':
            capture_end_page_image()
            print("请重新运行脚本开始监控")
            return
    
    # 获取播放器窗口
    hwnd, window_rect = get_player_window_rect()
    if not hwnd or not window_rect:
        print("无法找到播放器窗口")
        return
    
    # 获取当前视频标题
    if not current_video:
        current_video = get_current_video_title()
        if current_video:
            print(f"当前播放: {current_video}")
            video_history.append(current_video)
            save_state()
    
    print("="*50)
    print("视频目录自动播放助手")
    print(f"当前视频: {current_video}")
    print(f"已完成: {len(completed_videos)}个视频")
    print("="*50)
    print("🛑 按Ctrl+C停止程序")
    
    try:
        while True:
            # 获取播放器窗口位置
            hwnd, window_rect = get_player_window_rect()
            if not hwnd or not window_rect:
                print(f"窗口未找到，{CHECK_INTERVAL}秒后重试...")
                time.sleep(CHECK_INTERVAL)
                continue
            
            # 捕获播放器窗口区域
            screenshot = capture_window_region(window_rect)
            if screenshot is None:
                print(f"截图失败，{CHECK_INTERVAL}秒后重试...")
                time.sleep(CHECK_INTERVAL)
                continue
            
            # 检测结束页面
            end_detected = False
            
            # 图像匹配
            if os.path.exists(END_PAGE_IMAGE):
                end_detected = image_detected(screenshot, END_PAGE_IMAGE)
            
            # 文字识别
            if not end_detected and TEXT_TRIGGERS:
                text = image_to_text(screenshot)
                if any(trigger in text for trigger in TEXT_TRIGGERS):
                    end_detected = True
            
            # 处理结束
            if end_detected:
                handle_video_end(window_rect)
            
            # 更新当前视频标题（防止中途更改）
            new_title = get_current_video_title()
            if new_title and new_title != current_video:
                print(f"检测到视频切换: {current_video} -> {new_title}")
                current_video = new_title
                if current_video not in video_history:
                    video_history.append(current_video)
                save_state()
            
            time.sleep(CHECK_INTERVAL)
            
    except KeyboardInterrupt:
        print("\n退出程序")
        save_state()

if __name__ == "__main__":
    main()